www.gusucode.com > 基于Visual C++高级界面特效制作百例源码程序 > 基于Visual C++高级界面特效制作百例源码程序/code/char19/TabView/splitterTabWnd.cpp
/* FILNAME: splitterTabWnd.cpp PURPOSE: Manage view's that you can switch between by clicking at the tab. CREATED BY: Per Ghosh ENVIRONMENT: Visual C++ INFO: */ #include "stdafx.h" #include "tab.h" #include "TabView.h" #include "splitterTabWnd.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif IMPLEMENT_DYNCREATE(CsplitterTabWnd, CSplitterWnd) /************************************************ * Constructor/Destructor * * * * *** * */ CsplitterTabWnd::CsplitterTabWnd() : m_pwndTab(NULL), m_uSelectedViewIndex(0) { m_cxSplitter = m_cySplitter = 0; // size of splitter bar m_cxSplitterGap = m_cySplitterGap = 0; // amount of space between panes m_cxBorder = m_cyBorder = 0; // borders in client area } CsplitterTabWnd::~CsplitterTabWnd() { if( m_pwndTab ) delete m_pwndTab; } /************************************************ * Virtual functions * * * * *** * */ /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: Return: */ void CsplitterTabWnd::RecalcLayout() { CWnd* pWnd; CRect rectClient; HDWP hdwp; GetClientRect( rectClient ); // Set position for the tab window pWnd = GetPane( 1, 0 ); hdwp = ::BeginDeferWindowPos( 2 ); DeferWindowPos( hdwp, pWnd->m_hWnd, NULL, rectClient.left, rectClient.bottom - m_pwndTab->GetHeight(), rectClient.right, m_pwndTab->GetHeight(), SWP_NOACTIVATE|SWP_NOZORDER ); // Set position for the working-window pWnd = GetPane( 0, 0 ); DeferWindowPos( hdwp, pWnd->m_hWnd, NULL, rectClient.left, rectClient.top, rectClient.right, rectClient.bottom - m_pwndTab->GetHeight(), SWP_NOACTIVATE|SWP_NOZORDER ); EndDeferWindowPos( hdwp ); } /************************************************ * Functions * * * * *** * */ /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: Return: */ BOOL CsplitterTabWnd::Create( CWnd* pwndParent, CCreateContext* pContext ) { ASSERT( m_ptrarrayRCView.GetSize() ); // must be one or more ASSERT( pwndParent->IsKindOf( RUNTIME_CLASS( CFrameWnd ) ) ); CRuntimeClass* pRCView; // runtime class for first working view SIZE size; // CRect rect; // pRCView = (CRuntimeClass*)m_ptrarrayRCView[0]; ASSERT( pRCView->IsDerivedFrom( RUNTIME_CLASS( CWnd ) ) ); CreateStatic( pwndParent, 2, 1, WS_CHILD ); // create two panes pwndParent->GetClientRect( &rect ); // get rect for frame window size.cx = rect.right; size.cy = rect.bottom - 20; VERIFY( CreateView( 0, 0, pRCView, size, pContext ) ); size.cy = 20; VERIFY( CreateView( 1, 0, RUNTIME_CLASS(CwndTab), size, pContext ) ); m_pwndTab = (CwndTab*)GetPane( 1, 0 ); m_pwndTab->SetSplitterTabWnd( this ); ShowWindow( SW_SHOWNORMAL ); UpdateWindow(); return TRUE; } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: Return: */ UINT CsplitterTabWnd::AddView( CRuntimeClass* pRCView, LPCTSTR pszViewName ) { ASSERT( pRCView->IsDerivedFrom( RUNTIME_CLASS( CWnd ) ) ); m_ptrarrayRCView.Add( pRCView ); m_sarrayViewName.Add( pszViewName ); if( m_pwndTab ) m_pwndTab->SetModified(); return m_ptrarrayRCView.GetSize(); } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: */ void CsplitterTabWnd::InsertView( UINT uIndex, CRuntimeClass* pRCView, LPCTSTR pszViewName ) { ASSERT( pRCView->IsDerivedFrom( RUNTIME_CLASS( CWnd ) ) ); ASSERT( uIndex < 100 ); // Realistic ASSERT( uIndex < (UINT)m_ptrarrayRCView.GetSize() ); if( uIndex <= m_uSelectedViewIndex ) m_uSelectedViewIndex++; m_ptrarrayRCView.InsertAt( (int)uIndex, pRCView ); m_sarrayViewName.InsertAt( (int)uIndex, pszViewName ); if( m_pwndTab ) m_pwndTab->SetModified(); } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: */ void CsplitterTabWnd::SelectView( UINT uIndex ) { ASSERT( uIndex < (UINT)m_ptrarrayRCView.GetSize() ); ReplaceView( (CRuntimeClass*)m_ptrarrayRCView[uIndex] ); m_uSelectedViewIndex = uIndex; if( m_pwndTab ) m_pwndTab->Invalidate(); } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: */ void CsplitterTabWnd::RemoveView( CRuntimeClass* pRCView ) { int iIndex; CRuntimeClass* pRCViewInList; iIndex = m_ptrarrayRCView.GetSize(); while( iIndex ) { pRCViewInList = (CRuntimeClass*)m_ptrarrayRCView[iIndex]; if( pRCViewInList == pRCView ) { ASSERT( m_uSelectedViewIndex != (UINT)iIndex ); m_ptrarrayRCView.RemoveAt( iIndex ); if( m_pwndTab ) { m_pwndTab->SetModified(); m_pwndTab->Invalidate(); }// endif }// endif }// endwhile TRACE1("CsplitterTabWnd::RemoveView()\nWarning: Did not find %s\n", pRCView->m_lpszClassName ); } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: Param: */ void CsplitterTabWnd::RemoveView( UINT uIndex ) { ASSERT( uIndex < 100 ); // Realistic ASSERT( uIndex < (UINT)m_ptrarrayRCView.GetSize() ); ASSERT( m_uSelectedViewIndex != uIndex ); m_ptrarrayRCView.RemoveAt( (int)uIndex ); if( m_pwndTab ) { m_pwndTab->SetModified(); m_pwndTab->Invalidate(); } } /*------------------------------------------------------------------------------------------------- Name: ReplaceView() Type: Function Purpose: Destroy current working view and creates a new Param: pViewClass = Pekare till CRuntimeClass'en f?r den view som vi skall skapa Info: Med denna funktion tar vi och byter den view som finns i huvudf?nstret. Den view som tidigare d?r raderas vilket ocks? betyder att dess destruktor anropas. */ BOOL CsplitterTabWnd::ReplaceView(CRuntimeClass* pRCView) { CCreateContext context; // For connecting to document and creating view CView* pviewCurrent; // Current active view CView* pviewNew; // View that are going to be created BOOL bSaveAutoDelete; // For storing auto delete flag SIZE size; // Size for new view CRect rect; // Client rect VERIFY( pviewCurrent = (CView*)GetPane( 0, 0 ) ); // Get Window if( pviewCurrent->IsKindOf( pRCView ) ) return TRUE; // same as before pviewCurrent->GetClientRect( &rect ); // get rect size.cx = rect.right; // width size.cy = rect.bottom; // height CDocument* pDoc = pviewCurrent->GetDocument(); // get document if( pDoc ) // if document { bSaveAutoDelete = pDoc->m_bAutoDelete; // save auto delete flag pDoc->m_bAutoDelete = FALSE; // don't delete document } pviewCurrent->DestroyWindow(); // destroy view if( pDoc ) { pDoc->m_bAutoDelete = bSaveAutoDelete; // restore auto delete flag } // *** // Set connections for the new view // *** context.m_pNewViewClass = pRCView; context.m_pCurrentDoc = pDoc; context.m_pNewDocTemplate = pDoc->GetDocTemplate(); context.m_pLastView = NULL; context.m_pCurrentFrame = GetParentFrame(); if( ! CreateView( 0, 0, pRCView, size, &context) ) // create view in working pane { TRACE0("Warning: View was not created !!!\n"); return FALSE; } pviewNew = (CView*)GetPane( 0, 0 ); // get view in working pane RecalcLayout(); // reposition pviewNew->UpdateWindow(); // update GetParentFrame()->SetActiveView(pviewNew); // activate return TRUE; } BEGIN_MESSAGE_MAP(CsplitterTabWnd, CSplitterWnd) //{{AFX_MSG_MAP(CsplitterTabWnd) ON_WM_LBUTTONDOWN() ON_WM_SETCURSOR() ON_WM_MOUSEMOVE() //}}AFX_MSG_MAP END_MESSAGE_MAP() /************************************************ * Messages * * * * *** * */ /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: */ void CsplitterTabWnd::OnLButtonDown(UINT nFlags, CPoint point) { // prevent the user from dragging the splitter bar return; } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: */ BOOL CsplitterTabWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // Don't allow the cursor to change over splitbar return FALSE; } /*------------------------------------------------------------------------------------------------- Name: Type: Purpose: */ void CsplitterTabWnd::OnMouseMove(UINT nFlags, CPoint point) { // Don't allow the cursor to change over splitbar CWnd::OnMouseMove(nFlags, point); } /************************************************ ************************************************* ****** ****** **** **** **** class CwndTab **** **** **** ****** ****** ************************************************* ************************************************/ IMPLEMENT_DYNCREATE( CwndTab, CWnd ); CString CwndTab::m_stringWindowClass; /************************************************ * Constructor/Destructor * * * * *** * */ CwndTab::CwndTab() : m_dwFlag(0), m_uHeight(15), m_bTabModified(TRUE), m_pFont(NULL), m_iOffsetToLeft(20), m_uOffsetFontGap(3) { } CwndTab::~CwndTab() { if( m_dwFlag & PG_WNDTAB_FONT ) delete m_pFont; } /*------------------------------------------------------------------------------------------------- Name: SetHeight() Type: Function Purpose: Set height for tabs Param: uHeight = tab height */ void CwndTab::SetHeight( UINT uHeight ) { m_uHeight = uHeight; Invalidate(); } /************************************************ * Virtual functions * * * * *** * */ /*------------------------------------------------------------------------------------------------- Name: PreCreateWindow() Type: Virtual function Purpose: Register a new window class */ BOOL CwndTab::PreCreateWindow(CREATESTRUCT& cs) { if( CwndTab::m_stringWindowClass.IsEmpty() ) { CwndTab::m_stringWindowClass = ::AfxRegisterWndClass( CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW, AfxGetApp()->LoadStandardCursor(IDC_ARROW), (HBRUSH)(COLOR_BTNFACE+1), NULL ); } cs.lpszClass = CwndTab::m_stringWindowClass; return CWnd::PreCreateWindow(cs); } /************************************************ * Functions * * * * *** * */ /*------------------------------------------------------------------------------------------------- Name: CreateFont() Type: Function Purpose: Create font for text on tabs */ void CwndTab::CreateFont() { LOGFONT logfont; memset( &logfont, 0, sizeof( LOGFONT ) ); logfont.lfHeight = m_uHeight - 2; strcpy(logfont.lfFaceName,"MS Sans Serif"); m_pFont = new CFont(); m_pFont->CreateFontIndirect(&logfont); m_dwFlag |= PG_WNDTAB_FONT; } /*------------------------------------------------------------------------------------------------- Name: DrawTab() Type: Function Purpose: Draw all the tabs Param: pDC = DC that the tabs should be drawn on. */ void CwndTab::DrawTab( CDC* pDC ) { UINT uTabIndex; // tab that are drawn POINT ppoint[4]; // points that will be used to draw tab UINT uTabHeight; // the tab height UINT uDistanceToNextTab; // distance between tabs int iOffsetToLeft; // distance from left side of client edge CRect rect; CPen penBlack( PS_SOLID, 1, RGB(0,0,0) ); CPen* ppenOld; if( m_bTabModified ) UpdateTabWidth( pDC ); // update tab ? ppenOld = pDC->SelectObject( &penBlack ); // select a black pen pDC->SetBkMode( TRANSPARENT ); // just text GetClientRect( &rect ); // get client rect pDC->MoveTo( rect.left, rect.top ); // move to upper left pDC->LineTo( rect.right, rect.left ); // draw a line from left to right uTabHeight = m_uHeight - 1; uDistanceToNextTab = uTabHeight / 2; iOffsetToLeft = m_iOffsetToLeft; for( uTabIndex = 0; uTabIndex < (UINT)m_dwarrayTabWidth.GetSize(); uTabIndex++ ) { // *** // set all points for tab, then we will be able to draw it // *** ppoint[0].x = iOffsetToLeft; // "" ppoint[0].y = 0; iOffsetToLeft += uDistanceToNextTab; // "\" ppoint[1].x = iOffsetToLeft; ppoint[1].y = uTabHeight; //draw tab-text pDC->TextOut( ppoint[1].x + m_uOffsetFontGap, 1, m_psplitterTabWnd->m_sarrayViewName[uTabIndex] ); iOffsetToLeft += m_dwarrayTabWidth[uTabIndex]; // "\____" ppoint[2].x = iOffsetToLeft; ppoint[2].y = uTabHeight; if( uTabIndex == (UINT)(m_dwarrayTabWidth.GetSize() - 1) ) // "\____/" { iOffsetToLeft += uDistanceToNextTab; ppoint[3].x = iOffsetToLeft; ppoint[3].y = 0; } else { iOffsetToLeft += (uDistanceToNextTab / 2); ppoint[3].x = iOffsetToLeft; ppoint[3].y = (uTabHeight / 2); iOffsetToLeft -= (uDistanceToNextTab / 2); } pDC->Polyline( ppoint, 4 ); } pDC->SelectObject( ppenOld ); } /*------------------------------------------------------------------------------------------------- Name: DrawSelectedTab Type: Function Purpose: Draw the tab for selected view Param: pDC = DC that the tabs should be drawn on. */ void CwndTab::DrawSelectedTab( CDC* pDC ) { CRgn rgn; // filling region CBrush brush; // brush that the selected tab will be filled with UINT uTabHeight; // the tab height UINT uDistanceToNextTab; // distance between tabs int iOffsetToLeft; // distance from left side of client edge POINT ppoint[4]; // points that will be used to draw tab uTabHeight = m_uHeight - 1; // set tab height uDistanceToNextTab = uTabHeight / 2; // distance to next tab iOffsetToLeft = m_iOffsetToLeft; // distance to left side // *** loop to selected tab *** for( UINT uCounter = 0; uCounter < m_psplitterTabWnd->m_uSelectedViewIndex; uCounter++ ) { iOffsetToLeft += m_dwarrayTabWidth[uCounter]; iOffsetToLeft += uDistanceToNextTab; } // *** // set all points for selected tab, then we will be able to draw it // *** ppoint[0].x = iOffsetToLeft; // "" ppoint[0].y = 0; iOffsetToLeft += uDistanceToNextTab; // "\" ppoint[1].x = iOffsetToLeft; ppoint[1].y = uTabHeight; iOffsetToLeft += m_dwarrayTabWidth[uCounter]; // "\____" ppoint[2].x = iOffsetToLeft; ppoint[2].y = uTabHeight; iOffsetToLeft += uDistanceToNextTab; // "\____/" ppoint[3].x = iOffsetToLeft; ppoint[3].y = 0; brush.CreateSolidBrush( ::GetSysColor( COLOR_WINDOW ) ); rgn.CreatePolygonRgn( ppoint, 4, ALTERNATE ); pDC->FillRgn( &rgn, &brush ); pDC->Polyline( ppoint, 4 ); pDC->TextOut( ppoint[1].x + m_uOffsetFontGap, 1, m_psplitterTabWnd->m_sarrayViewName[uCounter] ); } /*------------------------------------------------------------------------------------------------- Name: UpdateTabWidth() Type: Function Purpose: Update widenes for all tabs Param: pDC = DC that the tabs should be drawn on. */ void CwndTab::UpdateTabWidth( CDC* pDC ) { CSize size; m_dwarrayTabWidth.RemoveAll(); for( int iCounter = 0; iCounter < m_psplitterTabWnd->m_sarrayViewName.GetSize(); iCounter++ ) { // get text size size = pDC->GetTextExtent( m_psplitterTabWnd->m_sarrayViewName[iCounter] ); // add the width for text plus gap to array m_dwarrayTabWidth.Add( size.cx + (m_uOffsetFontGap << 1) ); } m_bTabModified = FALSE; // tabs updated } BEGIN_MESSAGE_MAP(CwndTab, CWnd) //{{AFX_MSG_MAP(CwndTab) ON_WM_PAINT() ON_WM_LBUTTONDOWN() //}}AFX_MSG_MAP END_MESSAGE_MAP() /************************************************ * Messages * * * * *** * */ /*------------------------------------------------------------------------------------------------- Name: OnPaint() Type: Message Purpose: Draw all the information in the tab window */ void CwndTab::OnPaint() { CFont* pfontOld; // pointer to old font CPaintDC dc(this); // device context for painting if( m_pFont == NULL ) CreateFont(); // if no tab font, create one pfontOld = dc.SelectObject( m_pFont ); // select tab font DrawTab( &dc ); // draw the tabs DrawSelectedTab( &dc ); // draw th selected tab dc.SelectObject( pfontOld ); // select old font } /*------------------------------------------------------------------------------------------------- Name: OnLButtonDown() Type: Message Purpose: Check if klicked on a tab, and if so switch view */ void CwndTab::OnLButtonDown(UINT nFlags, CPoint point) { int iOffsetToLeft; UINT uDistanceToNextTab; uDistanceToNextTab = (m_uHeight - 1) / 2; iOffsetToLeft = m_iOffsetToLeft; // *** check if clicked on a tab *** for( UINT uCounter = 0; uCounter < (UINT)m_dwarrayTabWidth.GetSize(); uCounter++ ) { iOffsetToLeft += uDistanceToNextTab; if( ( point.x >= (iOffsetToLeft - 1) ) && ( point.x <= (int)(iOffsetToLeft + m_dwarrayTabWidth[uCounter] + 1) ) ) { m_psplitterTabWnd->SelectView( uCounter ); break; } iOffsetToLeft += m_dwarrayTabWidth[uCounter]; } CWnd::OnLButtonDown(nFlags, point); }